#include <iostream>
#include "FutureEye.h"
#include "vosmSubSystem.h"
#include "MSFaceDetector.h"
#include "BCMIGenderSubSystem.h"
#include "NaiveTimer.h"
#include "EOFCapture/EOFCapture.h"
#include "DepthTracker/DepthTracker.h"
#include "utils/Color2GrayMapper.h"

using namespace std;
using namespace cv;

IDetector *FutureEye::mDetector = NULL;
IExtractor *FutureEye::mExtractor = NULL;
IRecognizer *FutureEye::mRecognizer = NULL;
GuiHelper *FutureEye::mGuiHelper = NULL;
bool FutureEye::inited = false;
FutureEye *FutureEye::me = NULL;

DepthTracker dt;

bool workOnColorFace( Mat& img )
{
	TObject face;
	static NaiveTimer timer;
	timer.start();
	if (FutureEye::GetDetector()->detect(img, face)) {
// 		timer.showTillNow("detection time");
		face.drawOn(img);
		TObject plist;
		FutureEye::GetRecognizer()->recognize(img, face, plist);
// 		timer.showTillNow("recognize time");
		plist.draw(img);
	}

	return false;
}

Rect getFaceRect(const Mat& srcMat) {
	Rect rect;
// 	for (int i=0; i<srcMat.rows; ++i) {
// 		const uchar *ptr = srcMat.ptr();
// 		for (int j=0; j<srcMat.cols; ++j, ptr) {
// 
// 		}
// 	}
	return rect;
}

bool workOnColorDepthGray(Mat& color, Mat& depth, Mat& gray) {
	Color2GrayMapper *mapper = Color2GrayMapper::GetInstance();
	TObject face;
	FutureEye::GetDetector()->detect(color, face);
	face.drawOn(color);
	imshow("color", color);
	Rect rect = dt.tracking(depth);
	rectangle(depth, rect, Scalar(32767));
	imshow("depth", depth);

	Rect headRect;
	Mat headOnGray = mapper->mapping(color, depth, rect, headRect);

	rectangle(gray, headRect, Scalar(255));
	imshow("gray", gray);
	
	TObject plist;
// 	face.setRect(rect);
// 	FutureEye::GetRecognizer()->recognize(color, face, plist);
// 	plist.draw(color);
// 	imshow("with alignment", color);

	face.setRect(headRect);
	FutureEye::GetRecognizer()->recognize(gray, face, plist);
	plist.draw(gray);
	imshow("with alignment", gray);



	return false;
}

FutureEye *FutureEye::GetInstance(void) {
	if (me == NULL)
		me = new FutureEye;
	return me;
}

FutureEye::FutureEye(void)
{
}

FutureEye::~FutureEye(void)
{
}

bool FutureEye::init( string configFile) {
	configger.load(configFile);
	
	if (configger.detectorName == "MSFaceDetector") {
		mDetector = new MSFaceDetector;
	}
	else if (configger.detectorName == "VOSM") {
		mDetector = vosmSubSystem::getInstance();
	}

	if (configger.extractorName == "BCMIGender") {
		mExtractor = BCMIGenderSubSystem::getInstance();
	}

	if (configger.recognizerName == "VOSM") {
		mRecognizer = vosmSubSystem::getInstance();
	}
	else if (configger.extractorName == "BCMIGender") {
		mRecognizer = BCMIGenderSubSystem::getInstance();
	}

	mGuiHelper = GuiHelper::getInstance();
	return true;
}

void FutureEye::dealImage( const string& filename )
{
	Mat img;

	mGuiHelper->createWindow();

	img = imread(filename);

	workOnColorFace(img);

	mGuiHelper->draw(img);

	waitKey(0);

	destroyAllWindows();
}

void FutureEye::dealVideo( const string& filename )
{
	VOSMFaceComp face;
// 	VideoCapture capture;
// 	if (filename.length() == 0)
// 		capture.open(-1);
// 	else
// 		capture.open(filename);
// 
// 	if (capture.isOpened() == false) {
// 		cout << "capture open error." << endl;
// 	}

	EOFCapture myCapture;
	ColorReader cr;
	myCapture.SetCapture(&cr, DEVICE_TYPE_FILE_COLOR);
	DepthReader dr;
	myCapture.SetCapture(&dr, DEVICE_TYPE_FILE_DEPTH);
	GrayReader gr;
	myCapture.SetCapture(&gr, DEVICE_TYPE_FILE_GRAY);

	myCapture.Retrieve();

	Mat img;
	Mat depth;
	Mat gray;

	mGuiHelper->createWindow();

	while (true) {
		if (myCapture.Retrieve() == false) {
			cout << "device retrieve error." << endl;
			break;
		}
		myCapture.SelectFrame(DEVICE_TYPE_FILE_COLOR, img);
		myCapture.SelectFrame(DEVICE_TYPE_FILE_DEPTH, depth);
		myCapture.SelectFrame(DEVICE_TYPE_FILE_GRAY, gray);
// 		workOnColorFace(img);
		workOnColorDepthGray(img, depth, gray);
 		mGuiHelper->draw(img);
		char c = waitKey(1000/30);
		if (c == 27) break;
	}
	destroyAllWindows();

}


void FutureEye::startup( void )
{
	mDetector->loadDetector();

	mRecognizer->loadRecognizer();

	switch (configger.inputType) {
	case 2:
		dealImage(configger.imageFile);
		break;
	case 1:
		dealVideo(configger.videoFile);
		break;
	case 0://camera
		dealVideo("");
		break;
	}
}

void FutureEye::train( void )
{
	if (configger.detectorName == configger.recognizerName) {
		ISubSystem *subsys = dynamic_cast<ISubSystem *>(mDetector);
		if (NULL != subsys) {
			cout << "training subsystem success?: " << subsys->train() << endl;
			return;
		}
	}
	if (configger.trainDetector) {
		cout << "training detector success?: " << mDetector->train() << endl;
	}
	if (configger.trainRecognizer) {
		cout << "training recognizer success?: " << mRecognizer->train() << endl;
	}
}

void FutureEye::setVideo( string filename )
{
	configger.inputType = true;
	configger.videoFile = filename;
}

IDetector *FutureEye::GetDetector(void) {
	return mDetector;
}

IExtractor *FutureEye::GetExtractor(void) {
	return mExtractor;
}

IRecognizer *FutureEye::GetRecognizer(void) {
	return mRecognizer;
}

GuiHelper *FutureEye::GetGuiHelper(void) {
	return mGuiHelper;
}
